<?php


namespace App\Worker;


use App\Core\Ioc;
use App\Topics\Topics;
use Swoole\Process;

class Worker
{
    const WORKER = 'php-ps:';

    protected $app;

    protected $pid;

    protected $topic;

    protected $workers = [];

    public function __construct(Ioc $app, Topics $topic)
    {
        $this->app = $app;
        $this->topic = $topic;

        $this->pid = getmypid();

        swoole_set_process_name(sprintf('%s-%s-Master', self::WORKER, $topic->name));
    }


    public function start()
    {
        for ($i = 0; $i < $this->topic->process_num; $i++) {
            $this->runTopicProcess($i);
        }
        $this->processWait();
    }

    protected function runTopicProcess($i)
    {
        $process = new \swoole_process(function ($worker) use ($i) {
            swoole_set_process_name(sprintf("%s-%s-Worker-%d", self::WORKER, $this->topic->name, $i));

            $this->checkMpid($worker);

            $this->topic->handler($this->app);

        }, false, false);
        $pid = $process->start();
        $this->workers[$i] = $pid;
        return $pid;
    }


    protected function checkMpid(Process &$worker)
    {
        if (!\swoole_process::kill($this->pid, 0)) {
            $worker->exit();
        }
    }

    protected function rebootProcess($ret)
    {
        $pid = $ret['pid'];
        $index = array_search($pid, $this->workers);
        if ($index !== false) {
            $index = intval($index);
            $new_pid = $this->runTopicProcess($index);
            echo "rebootProcess: {$index}={$new_pid} Done\n";
            return;
        }
        throw new \Exception('rebootProcess Error: no pid');
    }

    protected function processWait()
    {
        while (1) {
            if (count($this->workers)) {
                $ret = \swoole_process::wait();
                if ($ret) {
                    $this->rebootProcess($ret);
                }
            }
        }
    }
}